package com.bluetrum.abmate;

import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.SwitchCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;

import com.bluetrum.abmate.cmd.SimpleRequestCallback2;
import com.bluetrum.abmate.databinding.FragmentFunctionBinding;
import com.bluetrum.abmate.databinding.LayoutFunctionAncLevelBinding;
import com.bluetrum.abmate.databinding.LayoutFunctionDeviceBinding;
import com.bluetrum.abmate.databinding.LayoutFunctionEarbudsBinding;
import com.bluetrum.abmate.databinding.LayoutFunctionKeyBinding;
import com.bluetrum.abmate.databinding.LayoutFunctionSoundEffectBinding;
import com.bluetrum.abmate.dialog.DialogFragmentDeviceName;
import com.bluetrum.abmate.dialog.DialogFragmentSingleChoice;
import com.bluetrum.abmate.eq.EqActivity;
import com.bluetrum.abmate.eq.RemoteEqActivity;
import com.bluetrum.abmate.leaudio.LeAudioBisActivity;
import com.bluetrum.abmate.multipoint.MultipointActivity;
import com.bluetrum.abmate.ota.OtaActivity;
import com.bluetrum.abmate.utils.Utils;
import com.bluetrum.abmate.viewmodels.SharedViewModel;
import com.bluetrum.devicemanager.cmd.request.AncRequest;
import com.bluetrum.devicemanager.cmd.request.AntiWindNoiseRequest;
import com.bluetrum.devicemanager.cmd.request.BassEngineRequest;
import com.bluetrum.devicemanager.cmd.request.BluetoothNameRequest;
import com.bluetrum.devicemanager.cmd.request.ClearPairRecordRequest;
import com.bluetrum.devicemanager.cmd.request.FactoryResetRequest;
import com.bluetrum.devicemanager.cmd.request.FindDeviceRequest;
import com.bluetrum.devicemanager.cmd.request.KeyRequest;
import com.bluetrum.devicemanager.cmd.Request;
import com.bluetrum.devicemanager.cmd.request.LedSwitchRequest;
import com.bluetrum.devicemanager.cmd.request.SpatialAudioModeRequest;
import com.bluetrum.devicemanager.cmd.request.WorkModeRequest;
import com.bluetrum.devicemanager.models.ABDevice;
import com.bluetrum.devicemanager.models.BassEngineRange;
import com.google.android.material.slider.Slider;
import com.zhouyou.view.segmentedbar.Segment;
import com.zhouyou.view.segmentedbar.SegmentedBarView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import dagger.hilt.android.AndroidEntryPoint;
import timber.log.Timber;

@AndroidEntryPoint
public class FunctionFragment extends Fragment implements
        DialogFragmentDeviceName.DialogFragmentDeviceNameListener {

    private static final String DIALOG_FRAGMENT_KEY_FUNCTION     = "DIALOG_FRAGMENT_KEY_FUNCTION";
    private static final String DIALOG_FRAGMENT_RENAME_DEVICE    = "DIALOG_FRAGMENT_RENAME_DEVICE";
    private static final String DIALOG_FRAGMENT_WORK_MODE        = "DIALOG_FRAGMENT_WORK_MODE";
    private static final String DIALOG_FRAGMENT_LED_SETTINGS     = "DIALOG_FRAGMENT_LED_SETTINGS";
    private static final String DIALOG_FRAGMENT_MICROPHONE       = "DIALOG_FRAGMENT_MICROPHONE";

    private SharedViewModel mViewModel;

    private FragmentFunctionBinding binding;
    private LayoutFunctionAncLevelBinding layoutAncLevelBinding;
    private LayoutFunctionSoundEffectBinding layoutSoundEffectBinding;
    private LayoutFunctionKeyBinding layoutKeyBinding;
    private LayoutFunctionEarbudsBinding layoutEarbudsBinding;
    private LayoutFunctionDeviceBinding layoutDeviceBinding;

    /* ANC */
    private static final Integer ancLevelValueSegment = 1; // ANC LEVEL初始化默认值

    private String strAncLevelTransparency;
    private String strAncLevelOff;
    private String strAncLevelOn;

    /* 按键功能 */

    /* 耳机功能 */
    private String strMicSettingsAuto;
    private String strMicSettingsLeft;
    private String strMicSettingsRight;

    // 选框资源
    private String[] workModeStrings;
    private String[] keySettingStrings;
    private String[] ledSettingStrings;

    private void loadStrings() {
        strAncLevelTransparency = getString(R.string.function_anc_level_transparency);
        strAncLevelOff = getString(R.string.function_anc_level_off);
        strAncLevelOn = getString(R.string.function_anc_level_on);

        strMicSettingsAuto = getString(R.string.function_microphone_settings_auto);
        strMicSettingsLeft = getString(R.string.function_microphone_settings_left);
        strMicSettingsRight = getString(R.string.function_microphone_settings_right);

        // 选框资源
        workModeStrings = new String[] {
                getString(R.string.function_work_mode_normal),
                getString(R.string.function_work_mode_game),
        };
        keySettingStrings = new String [] { // 对应KeyRequest.KEY_FUNCTION_XXX
                getString(R.string.function_key_function_none),
                getString(R.string.function_key_function_recall),
                getString(R.string.function_key_function_voice_assistant),
                getString(R.string.function_key_function_previous),
                getString(R.string.function_key_function_next),
                getString(R.string.function_key_function_volume_up),
                getString(R.string.function_key_function_volume_down),
                getString(R.string.function_key_function_play_pause),
                getString(R.string.function_key_function_game_mode),
                getString(R.string.function_key_function_anc_mode),
        };
        ledSettingStrings = new String[] {
                getString(R.string.function_led_settings_all_off),
                getString(R.string.function_led_settings_red_always_on),
                getString(R.string.function_led_settings_blue_always_on),
                getString(R.string.function_led_settings_blue_slow_blink),
                getString(R.string.function_led_settings_blue_fast_blink),
                getString(R.string.function_led_settings_red_slow_blink),
                getString(R.string.function_led_settings_red_fast_blink),
                getString(R.string.function_led_settings_red_blue_slow_blink),
                getString(R.string.function_led_settings_red_blue_fast_blink),
        };
    }

    private void setClickEvents() {
        layoutDeviceBinding.clearRecordLayout.setOnClickListener(this::clickClearPairRecord);
        layoutDeviceBinding.restoreSettingsLayout.setOnClickListener(this::clickRestoreSettings);
        layoutDeviceBinding.updateFirmwareLayout.setOnClickListener(this::clickUpdateFirmware);
//        layoutEarbudsBinding.microphoneLayout.setOnClickListener(this::clickMicrophone);
//        layoutEarbudsBinding.ledSettingsLayout.setOnClickListener(this::clickLedSettings);
        layoutEarbudsBinding.multipointLayout.setOnClickListener(this::clickMultipoint);
        layoutEarbudsBinding.leAudioBisLayout.setOnClickListener(this::clickLeAudioBis);
        layoutEarbudsBinding.workModeLayout.setOnClickListener(this::clickWorkMode);
        layoutEarbudsBinding.renameDeviceLayout.setOnClickListener(this::clickRenameDevice);
        layoutEarbudsBinding.ledSwitch.setOnClickListener(this::clickLedSwitch);
        layoutEarbudsBinding.findDeviceSwitch.setOnClickListener(this::clickFindDeviceSwitch);
        layoutAncLevelBinding.ancSettingsButton.setOnClickListener(this::clickAncSetting);

        layoutSoundEffectBinding.eqLayout.setOnClickListener(this::clickEqualizerPreset);
        layoutSoundEffectBinding.bassEngineSwitch.setOnClickListener(this::clickBass);
        layoutSoundEffectBinding.bassValueSlider.addOnSliderTouchListener(new Slider.OnSliderTouchListener() {
            @Override
            public void onStartTrackingTouch(@NonNull Slider slider) {
            }

            @Override
            public void onStopTrackingTouch(@NonNull Slider slider) {
                clickBassSlider(slider);
            }
        });
        layoutSoundEffectBinding.spatialAudioSwitch.setOnClickListener(this::clickSpatialAudio);
        layoutSoundEffectBinding.antiWindNoiseSwitch.setOnClickListener(this::clickAntiWindNoise);

        layoutKeyBinding.leftSingleTapLayout.setOnClickListener(this::clickKeyFunction);
        layoutKeyBinding.leftDoubleTapLayout.setOnClickListener(this::clickKeyFunction);
        layoutKeyBinding.leftTripleTapLayout.setOnClickListener(this::clickKeyFunction);
        layoutKeyBinding.rightSingleTapLayout.setOnClickListener(this::clickKeyFunction);
        layoutKeyBinding.rightDoubleTapLayout.setOnClickListener(this::clickKeyFunction);
        layoutKeyBinding.rightTripleTapLayout.setOnClickListener(this::clickKeyFunction);
        layoutKeyBinding.leftLongPressLayout.setOnClickListener(this::clickKeyFunction);
        layoutKeyBinding.rightLongPressLayout.setOnClickListener(this::clickKeyFunction);
    }

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        mViewModel = new ViewModelProvider(this).get(SharedViewModel.class);
        binding = FragmentFunctionBinding.inflate(inflater, container, false);
        layoutAncLevelBinding = binding.layoutFunctionAncLevel;
        layoutSoundEffectBinding = binding.layoutFunctionSoundEffect;
        layoutKeyBinding = binding.layoutFunctionKey;
        layoutEarbudsBinding = binding.layoutFunctionEarbuds;
        layoutDeviceBinding = binding.layoutFunctionDevice;

        // 默认不启用麦克风，保留逻辑，隐藏界面
        layoutEarbudsBinding.microphoneLayout.setVisibility(View.GONE);

        loadStrings();
        setClickEvents();

        setupAncLevelSegmentedView();

        mViewModel.getActiveDevice().observe(getViewLifecycleOwner(), activeDevice -> {
            // 不论连接断开，复位视图
            layoutEarbudsBinding.findDeviceSwitch.setChecked(false);
        });

        setupDeviceStatus();

        return binding.getRoot();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }

    /**
     * 配置监听设备状态
     */
    private void setupDeviceStatus() {
        mViewModel.getDeviceName().observe(getViewLifecycleOwner(),
                deviceName -> layoutEarbudsBinding.renameDeviceDetail.setText(deviceName));

        mViewModel.getDeviceKeySettings().observe(getViewLifecycleOwner(), this::keySettingsChanged);

//        mViewModel.getDeviceVolume().observe(getViewLifecycleOwner(), volume -> {
//            Timber.d("Volume updated: %s", volume);
//        });
//
//        mViewModel.getDevicePlayState().observe(getViewLifecycleOwner(), playState -> {
//            Timber.d("Play State updated: %s", playState);
//        });

        mViewModel.getDeviceWorkMode().observe(getViewLifecycleOwner(), workMode -> {
            if (workMode == null) {
                layoutEarbudsBinding.workModeDetail.setText(null);
            } else if (workMode < workModeStrings.length) {
                String strWorkMode = workModeStrings[workMode];
                layoutEarbudsBinding.workModeDetail.setText(strWorkMode);
            }
        });

//        mViewModel.getDeviceInEarStatus().observe(getViewLifecycleOwner(), inEarStatus -> {
//            Timber.d("In-Ear Status updated: %s", inEarStatus);
//        });
//
//        mViewModel.getDeviceLanguageSetting().observe(getViewLifecycleOwner(), languageSetting -> {
//            Timber.d("Language updated: %s", languageSetting);
//        });
//
//        mViewModel.getDeviceAutoAnswer().observe(getViewLifecycleOwner(), autoAnswer -> {
//            Timber.d("Auto Answer updated: %s", autoAnswer);
//        });

        mViewModel.getDeviceAncMode().observe(getViewLifecycleOwner(), ancMode -> {
            Timber.d("ANC Mode: %s", ancMode);
            if (ancMode != null) {
                switch (ancMode) {
                    case AncRequest.ANC_MODE_OFF:
                        layoutAncLevelBinding.ancLevelSegmentedView.setValueSegment(1);
                        layoutAncLevelBinding.ancSettingsButton.setEnabled(false);
                        break;
                    case AncRequest.ANC_MODE_ON:
                        layoutAncLevelBinding.ancLevelSegmentedView.setValueSegment(2);
                        layoutAncLevelBinding.ancSettingsButton.setEnabled(true);
                        break;
                    case AncRequest.ANC_MODE_TRANSPARENCY:
                        layoutAncLevelBinding.ancLevelSegmentedView.setValueSegment(0);
                        layoutAncLevelBinding.ancSettingsButton.setEnabled(true);
                        break;
                }
                layoutAncLevelBinding.getRoot().setVisibility(View.VISIBLE);
            }
            // ANC not support
            else {
                layoutAncLevelBinding.getRoot().setVisibility(View.GONE);
            }
        });

        mViewModel.getDeviceAncGainNum().observe(getViewLifecycleOwner(), ancGainNum -> {
            Timber.d("ANC Gain Num: %s", ancGainNum);
            if (ancGainNum == null && mViewModel.getDeviceTransparencyGainNum().getValue() == null) {
                layoutAncLevelBinding.ancSettingsButton.setVisibility(View.GONE);
            } else {
                layoutAncLevelBinding.ancSettingsButton.setVisibility(View.VISIBLE);
            }
        });

        mViewModel.getDeviceTransparencyGainNum().observe(getViewLifecycleOwner(), transparencyGainNum -> {
            Timber.d("Transparency Gain Num: %s", transparencyGainNum);
            if (transparencyGainNum == null && mViewModel.getDeviceAncGainNum().getValue() == null) {
                layoutAncLevelBinding.ancSettingsButton.setVisibility(View.GONE);
            } else {
                layoutAncLevelBinding.ancSettingsButton.setVisibility(View.VISIBLE);
            }
        });

        mViewModel.getDeviceLedSwitch().observe(getViewLifecycleOwner(), ledOn -> {
            if (ledOn != null) {
                layoutEarbudsBinding.ledSwitch.setChecked(ledOn);
            }
        });

        mViewModel.getDeviceTwsConnected().observe(getViewLifecycleOwner(), twsConnected -> {
            Boolean leftIsMainSide = mViewModel.getDeviceLeftIsMainSide().getValue();
            updateDeviceKeyStatus(twsConnected, leftIsMainSide);
        });

        mViewModel.getDeviceLeftIsMainSide().observe(getViewLifecycleOwner(), leftIsMainSide -> {
            Boolean twsConnected = mViewModel.getDeviceTwsConnected().getValue();
            updateDeviceKeyStatus(twsConnected, leftIsMainSide);
        });

        mViewModel.getDeviceCapacities().observe(getViewLifecycleOwner(), deviceCapacities -> {
            if (deviceCapacities != null) {
                int spatialAudioVisibility = deviceCapacities.supportSpatialAudio() ? View.VISIBLE : View.GONE;
                int bassEngineVisibility = deviceCapacities.supportBassEngine() ? View.VISIBLE : View.GONE;
                int antiWindNoiseVisibility = deviceCapacities.supportAntiWindNoise() ? View.VISIBLE : View.GONE;
                int multipointVisibility = deviceCapacities.supportMultipoint() ? View.VISIBLE : View.GONE;
                int leAudioBisVisibility = deviceCapacities.supportLeAudioBis() ? View.VISIBLE : View.GONE;

                layoutSoundEffectBinding.spatialAudioLayout.setVisibility(spatialAudioVisibility);
                layoutSoundEffectBinding.bassEngineLayout.setVisibility(bassEngineVisibility);
                layoutSoundEffectBinding.antiWindNoiseLayout.setVisibility(antiWindNoiseVisibility);
                layoutEarbudsBinding.multipointLayout.setVisibility(multipointVisibility);
                layoutEarbudsBinding.leAudioBisLayout.setVisibility(leAudioBisVisibility);
            } else {
                layoutSoundEffectBinding.spatialAudioLayout.setVisibility(View.GONE);
                layoutSoundEffectBinding.bassEngineLayout.setVisibility(View.GONE);
                layoutSoundEffectBinding.antiWindNoiseLayout.setVisibility(View.GONE);
                layoutEarbudsBinding.multipointLayout.setVisibility(View.GONE);
                layoutEarbudsBinding.leAudioBisLayout.setVisibility(View.GONE);
            }
        });

        mViewModel.getDeviceSpatialAudioMode().observe(getViewLifecycleOwner(), mode -> {
            if (mode != null) {
                // 暂不支持头部追踪
                layoutSoundEffectBinding.spatialAudioSwitch.setChecked(mode.isOn());
            }
        });

        mViewModel.getDeviceBassEngineStatus().observe(getViewLifecycleOwner(), status -> {
            if (status != null) {
                layoutSoundEffectBinding.bassEngineSwitch.setChecked(status);
                if (status) {
                    layoutSoundEffectBinding.bassValueLayout.setVisibility(View.VISIBLE);
                } else {
                    layoutSoundEffectBinding.bassValueLayout.setVisibility(View.GONE);
                }
            } else {
                layoutSoundEffectBinding.bassValueLayout.setVisibility(View.GONE);
            }
        });

        mViewModel.getDeviceBassEngineValue().observe(getViewLifecycleOwner(), value ->
                updateBassEngine(mViewModel.getDeviceBassEngineRange().getValue(), value)
        );
        mViewModel.getDeviceBassEngineRange().observe(getViewLifecycleOwner(), range ->
                updateBassEngine(range, mViewModel.getDeviceBassEngineValue().getValue())
        );

        mViewModel.getDeviceAntiWindNoise().observe(getViewLifecycleOwner(), status -> {
            if (status != null) {
                layoutSoundEffectBinding.antiWindNoiseSwitch.setChecked(status);
            }
        });
    }

    private void updateBassEngine(BassEngineRange range, Integer value) {
        if (range != null && value != null) {
            Slider slider = layoutSoundEffectBinding.bassValueSlider;
            slider.setValueFrom(range.getMinValue());
            slider.setValueTo(range.getMaxValue());
            slider.setValue(value);
        }
    }

    private void updateDeviceKeyStatus(Boolean twsConnected, Boolean leftIsMainSide) {
        ViewGroup[] leftViews = new ViewGroup[] {
                layoutKeyBinding.leftSingleTapLayout,
                layoutKeyBinding.leftDoubleTapLayout,
                layoutKeyBinding.leftTripleTapLayout,
                layoutKeyBinding.leftLongPressLayout,
        };
        ViewGroup[] rightViews = new ViewGroup[] {
                layoutKeyBinding.rightSingleTapLayout,
                layoutKeyBinding.rightDoubleTapLayout,
                layoutKeyBinding.rightTripleTapLayout,
                layoutKeyBinding.rightLongPressLayout,
        };

        boolean leftEnable;
        boolean rightEnable;

        if (twsConnected != null) {
            if (twsConnected) {
                leftEnable = true;
                rightEnable = true;
            } else {
                if (leftIsMainSide != null) {
                    leftEnable = leftIsMainSide;
                    rightEnable = !leftIsMainSide;
                } else {
                    leftEnable = true;
                    rightEnable = true;
                }
            }
        } else {
            leftEnable = false;
            rightEnable = false;
        }

        for (ViewGroup leftView : leftViews) {
            Utils.enableControls(leftEnable, leftView);
        }
        for (ViewGroup rightView : rightViews) {
            Utils.enableControls(rightEnable, rightView);
        }
    }

    /* ANC功能 */

    private void setupAncLevelSegmentedView() {
        int[] colors = new int[]{
                Color.parseColor("#eaffc1"),
                Color.parseColor("#fcf8e7"),
                Color.parseColor("#62b8ee")
        };
        ArrayList<Segment> segments = new ArrayList<>();
        Segment segment0 = new Segment("", strAncLevelTransparency, colors[0]);
        segments.add(segment0);
        Segment segment1 = new Segment("", strAncLevelOff, colors[1]);
        segments.add(segment1);
        Segment segment2 = new Segment("", strAncLevelOn, colors[2]);
        segments.add(segment2);
        layoutAncLevelBinding.ancLevelSegmentedView.setShowDescriptionText(true);
        layoutAncLevelBinding.ancLevelSegmentedView.setValueSegment(ancLevelValueSegment);
        layoutAncLevelBinding.ancLevelSegmentedView.setSegments(segments);

        layoutAncLevelBinding.ancLevelSegmentedView.setClickable(true);
        layoutAncLevelBinding.ancLevelSegmentedView.setOnlyUpdateWhenTouchUp(true);
        layoutAncLevelBinding.ancLevelSegmentedView.setListener(new SegmentedBarView.SegmentedBarViewListener() {
            @Override
            public void onValueChanged(Float value, boolean fromUser) {}

            @Override
            public void onValueSegmentChanged(Integer valueSegment, boolean fromUser) {
                Timber.v("onValueSegmentChanged: %s, fromUser: %s", valueSegment, fromUser);
                if (fromUser) {
                    byte ancMode;
                    switch (valueSegment) {
                        case 0: ancMode = AncRequest.ANC_MODE_TRANSPARENCY; break;
                        case 1: ancMode = AncRequest.ANC_MODE_OFF; break;
                        case 2: ancMode = AncRequest.ANC_MODE_ON; break;
                        default: return;
                    }
                    Request request = AncRequest.modeRequest(ancMode);;
                    sendRequestAndWaitSuccess(request, null);
                }
            }
        });
    }

    private void clickAncSetting(View v) {
        final Intent intent = new Intent(requireContext(), AncSettingsActivity.class);
        startActivity(intent);
    }

    /* 音效 */

    // 低音
    private void clickBass(View view) {
        SwitchCompat switchCompat = (SwitchCompat) view;
        BassEngineRequest request = BassEngineRequest.enableRequest(switchCompat.isChecked());
        sendRequestAndWaitSuccess(request, null);
    }

    // 低音值
    private void clickBassSlider(Slider slider) {
        byte value = (byte) slider.getValue();
        BassEngineRequest request = BassEngineRequest.valueRequest(value);
        sendRequestAndWaitSuccess(request, null);
    }

    // 空间音频
    private void clickSpatialAudio(View view) {
        SwitchCompat switchCompat = (SwitchCompat) view;
        SpatialAudioModeRequest request = new SpatialAudioModeRequest(switchCompat.isChecked());
        sendRequestAndWaitSuccess(request, null);
    }

    // 抗风噪
    private void clickAntiWindNoise(View view) {
        SwitchCompat switchCompat = (SwitchCompat) view;
        AntiWindNoiseRequest request = new AntiWindNoiseRequest(switchCompat.isChecked());
        sendRequestAndWaitSuccess(request, null);
    }

    // LE Audio BIS
    private void clickLeAudioBis(View view) {
        Intent intent = new Intent(requireContext(), LeAudioBisActivity.class);
        startActivity(intent);
    }

    /* 按键功能 */

    @Nullable
    private TextView getTextViewFromKeyType(int keyType) {
        switch (keyType) {
            case KeyRequest.KEY_LEFT_SINGLE_TAP: return layoutKeyBinding.leftSingleTapFunction;
            case KeyRequest.KEY_RIGHT_SINGLE_TAP: return layoutKeyBinding.rightSingleTapFunction;
            case KeyRequest.KEY_LEFT_DOUBLE_TAP: return layoutKeyBinding.leftDoubleTapFunction;
            case KeyRequest.KEY_RIGHT_DOUBLE_TAP: return layoutKeyBinding.rightDoubleTapFunction;
            case KeyRequest.KEY_LEFT_TRIPLE_TAP: return layoutKeyBinding.leftTripleTapFunction;
            case KeyRequest.KEY_RIGHT_TRIPLE_TAP: return layoutKeyBinding.rightTripleTapFunction;
            case KeyRequest.KEY_LEFT_LONG_PRESS: return layoutKeyBinding.leftLongPressFunction;
            case KeyRequest.KEY_RIGHT_LONG_PRESS: return layoutKeyBinding.rightLongPressFunction;
        }
        return null;
    }

    private void keySettingsChanged(Map<Integer, Integer> keySettings) {
        Timber.v("Key: %s", keySettings);
        if (keySettings != null) {
            keySettings.entrySet().stream().forEach(keyEntry -> {
                Integer keyType = keyEntry.getKey();
                TextView keyFunctionTextView = getTextViewFromKeyType(keyType);
                if (keyFunctionTextView != null) {
                    Integer keyFunction = keyEntry.getValue();
                    final String keyFunctionDescription = keySettingStrings[keyFunction];
                    keyFunctionTextView.setText(keyFunctionDescription);
                }
            });
        }
    }

    final Map<Integer, Integer> keyViewMap = new HashMap<Integer, Integer>() {{
        put(R.id.left_single_tap_layout, (int) KeyRequest.KEY_LEFT_SINGLE_TAP);
        put(R.id.right_single_tap_layout, (int) KeyRequest.KEY_RIGHT_SINGLE_TAP);
        put(R.id.left_double_tap_layout, (int) KeyRequest.KEY_LEFT_DOUBLE_TAP);
        put(R.id.right_double_tap_layout, (int) KeyRequest.KEY_RIGHT_DOUBLE_TAP);
        put(R.id.left_triple_tap_layout, (int) KeyRequest.KEY_LEFT_TRIPLE_TAP);
        put(R.id.right_triple_tap_layout, (int) KeyRequest.KEY_RIGHT_TRIPLE_TAP);
        put(R.id.left_long_press_layout, (int) KeyRequest.KEY_LEFT_LONG_PRESS);
        put(R.id.right_long_press_layout, (int) KeyRequest.KEY_RIGHT_LONG_PRESS);
    }};

    private void clickKeyFunction(View view) {
        Integer keyType = keyViewMap.get(view.getId());
        Map<Integer, Integer> keySettings = mViewModel.getDeviceKeySettings().getValue();
        if (keyType != null && keySettings != null) {
            Integer keySetting = keySettings.get(keyType);
            if (keySetting != null) {
                DialogFragmentSingleChoice dialogFragmentSingleChoice
                        = DialogFragmentSingleChoice.newInstance(getString(R.string.function_key_select), keySettingStrings, keySetting, ((item, index) -> {
                    Timber.v("Key define: %s, %s", item, index);
                    updateKeyFunction(keyType.byteValue(), (byte) index);
                }));
                dialogFragmentSingleChoice.show(getChildFragmentManager(), DIALOG_FRAGMENT_KEY_FUNCTION);
            }
        }
    }

    private void updateKeyFunction(byte keyType, byte keyFunction) {
        startWaitingResponse();
        mViewModel.setKeySetting(keyType, keyFunction, new SimpleRequestCallback2() {
            @Override
            public void onComplete(boolean result) {
                stopWaitingResponse();
                if (result) {
                    Utils.showToast(requireContext(), R.string.request_succeeded);
                } else {
                    Utils.showToast(requireContext(), R.string.request_failed);
                }
            }

            @Override
            public void onTimeout() {
                stopWaitingResponse();
                Utils.showToast(requireContext(), R.string.request_timeout);
            }
        });
    }

    /* 均衡器 */

    private void clickEqualizerPreset(View view) {
        // 如果RemoteEqSettings为空，使用APP本地EQ设置
        // If RemoteEqSettings is nil, use App local EQ Settings
        if (mViewModel.getDeviceRemoteEqSettings().getValue() != null) {
            final Intent intent = new Intent(requireContext(), RemoteEqActivity.class);
            startActivity(intent);
        } else {
            final Intent intent = new Intent(requireContext(), EqActivity.class);
            startActivity(intent);
        }
    }

    /* 耳机功能 */

    // 一拖多
    private void clickMultipoint(View view) {
        final Intent intent = new Intent(requireContext(), MultipointActivity.class);
        startActivity(intent);
    }

    // 修改名称
    private void clickRenameDevice(View view) {
        final String deviceName = mViewModel.getDeviceName().getValue();
        DialogFragmentDeviceName dialogFragmentDeviceName
                = DialogFragmentDeviceName.newInstance(deviceName);
        dialogFragmentDeviceName.show(getChildFragmentManager(), DIALOG_FRAGMENT_RENAME_DEVICE);
    }

    // 工作模式
    private void clickWorkMode(View view) {
        int workMode = Optional.ofNullable(mViewModel.getDeviceWorkMode().getValue()).orElse((byte) 0);
        DialogFragmentSingleChoice dialogFragmentSingleChoice
                = DialogFragmentSingleChoice.newInstance(getString(R.string.function_work_mode_select), workModeStrings, workMode, ((item, index) -> {
            // index对应WorkModeRequest.WORK_MODE_xxx
            Request request = new WorkModeRequest((byte) index);
            sendRequestAndWaitSuccess(request, null);
        }));
        dialogFragmentSingleChoice.show(getChildFragmentManager(), DIALOG_FRAGMENT_WORK_MODE);
    }

    // 闪灯
    private void clickLedSwitch(View view) {
        SwitchCompat switchCompat = (SwitchCompat) view;
        LedSwitchRequest request = new LedSwitchRequest(switchCompat.isChecked());
        sendRequestAndWaitSuccess(request, null);
    }

    private void clickLedSettings(View view) {
        int checkedItem = 0;
        DialogFragmentSingleChoice dialogFragmentSingleChoice
                = DialogFragmentSingleChoice.newInstance(getString(R.string.function_led_settings_select), ledSettingStrings, checkedItem, ((item, index) -> {
            Utils.showToast(requireContext(), "需要固件支持");
            layoutEarbudsBinding.ledSettingsDetail.setText(item);
        }));
        dialogFragmentSingleChoice.show(getChildFragmentManager(), DIALOG_FRAGMENT_LED_SETTINGS);
    }

    // 3D音效
    private void clickSoundEffect3d(View view) {
        SwitchCompat switchCompat = (SwitchCompat) view;
        SpatialAudioModeRequest request = new SpatialAudioModeRequest(switchCompat.isChecked());
        sendRequestAndWaitSuccess(request, null);
    }

    // 麦克风
    private void clickMicrophone(View view) {
        final String[] microphoneSettings = {strMicSettingsAuto, strMicSettingsLeft, strMicSettingsRight};

        int checkedItem = 0;
        DialogFragmentSingleChoice dialogFragmentSingleChoice
                = DialogFragmentSingleChoice.newInstance(getString(R.string.function_microphone_settings_select), microphoneSettings, checkedItem, ((item, index) -> {
            Utils.showToast(requireContext(), "需要固件支持");
            layoutEarbudsBinding.microphoneDetail.setText(item);
        }));
        dialogFragmentSingleChoice.show(getChildFragmentManager(), DIALOG_FRAGMENT_MICROPHONE);
    }

    // 查找设备
    private void clickFindDeviceSwitch(View view) {
        SwitchCompat switchCompat = (SwitchCompat) view;
        FindDeviceRequest request = new FindDeviceRequest(switchCompat.isChecked());
        sendRequestAndWaitSuccess(request, null);
    }

    /* 设备功能 */

    // 升级固件
    private void clickUpdateFirmware(View view) {
        // 转到OTA升级
        ABDevice device = mViewModel.getActiveDevice().getValue();
        if (device != null) {
            final Intent i = new Intent(requireContext(), OtaActivity.class);
            startActivity(i);
        } else {
            Utils.showToast(requireContext(), R.string.ota_device_not_connected);
        }
    }

    // 恢复初始设置
    private void clickRestoreSettings(View view) {
        AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
        builder.setTitle(R.string.function_factory_reset_comfirm)
                .setPositiveButton(R.string.ok, ((dialog, which) -> {
            Request request = new FactoryResetRequest();
            sendRequestAndWaitSuccess(request, null);
        })).setNegativeButton(R.string.cancel, null).show();
    }

    // 清除配对记录
    private void clickClearPairRecord(View view) {
        AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
        builder.setTitle(R.string.function_clear_pair_record_confirm)
                .setPositiveButton(R.string.ok, ((dialog, which) -> {
                    Request request = new ClearPairRecordRequest();
                    sendRequestAndWaitSuccess(request, null);
                })).setNegativeButton(R.string.cancel, null).show();
    }

    // 修改名称回调
    @Override
    public boolean onDeviceNameUpdated(@NonNull String deviceName) {
        Timber.i("BT new name：%s", deviceName);
        Request request = new BluetoothNameRequest(deviceName);
        sendRequestAndWaitSuccess(request, new SimpleRequestCallback2() {
            @Override
            public void onComplete(boolean result) {
                if (result) {
                    // Alert Open Bluetooth Settings
                    AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
                    builder.setMessage(R.string.function_rename_complete_tip)
                            .setPositiveButton(R.string.ok, (dialog, which) -> startActivity(new Intent(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS)))
                            .setNegativeButton(R.string.cancel, null)
                            .setCancelable(false)
                            .show();
                }
            }

            @Override
            public void onTimeout() {

            }
        });
        return true;
    }

    /* Request */

    private void startWaitingResponse() {
        binding.progressIndicator.setVisibility(View.VISIBLE);
        binding.scrollView.setEnabled(false); // todo: 没用
    }

    private void stopWaitingResponse() {
        binding.progressIndicator.setVisibility(View.GONE);
        binding.scrollView.setEnabled(true); // todo: 没用
    }

    /*
    统一处理返回值Boolean的Request，并提示可能的失败和超时
     */
    private void sendRequestAndWaitSuccess(@NonNull final Request request,
                                           @Nullable SimpleRequestCallback2 callback2) {
        // todo: 加上发送等待画面
        startWaitingResponse();

        mViewModel.sendRequest(request, new SimpleRequestCallback2() {
            @Override
            public void onComplete(boolean result) {
                Timber.d("sendRequest result = %s", result);

                if (result) {
                    Utils.showToast(requireContext(), R.string.request_succeeded);
                } else {
                    Utils.showToast(requireContext(), R.string.request_failed);
                }

                // todo: 解除发送等待
                stopWaitingResponse();

                if (callback2 != null) {
                    callback2.onComplete(result);
                }
            }

            @Override
            public void onTimeout() {
                Timber.w("Request timeout");
                Utils.showToast(requireContext(), R.string.request_timeout);

                // todo: 解除发送等待
                stopWaitingResponse();

                if (callback2 != null) {
                    callback2.onTimeout();
                }
            }
        });
    }

}